package com.test.study.shiro_demo.config;


import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.test.study.shiro_demo.matcher.RetryLimitHashedCredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Bean("credentialsMatcher")
    public RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher(){
        RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher(ehCacheManager());

        //如果密码加密,可以打开下面配置
        //加密算法的名称
        retryLimitHashedCredentialsMatcher.setHashAlgorithmName("md5");
        //配置加密的次数
        retryLimitHashedCredentialsMatcher.setHashIterations(2);
        //是否存储为16进制
        //retryLimitHashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);

        return retryLimitHashedCredentialsMatcher;
    }

    //ShiroFilter过滤所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给ShiroFilter配置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //添加 Shiro 的内置过滤器=======================
        /*
            anon : 无需认证，就可以访问
            authc : 必须认证，才能访问
            user : 必须拥有 “记住我”功能才能用
            perms : 拥有对某个资源的权限才能访问
            role : 拥有某个角色权限才能访问
         */
        Map<String, String> map = new HashMap<String, String>();
        map.put("/login","anon");//放行
        // 设置认证界面路径
        map.put("/userLogin","anon");//放行
        map.put("/logout","logout");
        map.put("/index","authc");
        map.put("/**","authc");
        //设置默认登录页
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    //创建安全管理器
    @Bean(name = "SecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myRealm") Realm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        securityManager.setRealm(myRealm);
        /*
            AllSuccessfulStrategy 所有认证成功才能算成功
            FirstSuccessfulStrategy 第一次认证成功后后续不做认证
            AtLeastOneSuccessfulStrategy 只要有一个认证策略成功即可

            TODO 多Realm配置策略
              ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
            //设置组合的Realm策略
             modularRealmAuthenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
             securityManager.setAuthenticator(modularRealmAuthenticator);
             //创建多realm实例
             ArrayList<Realm> list=new ArrayList<>();
               list.add(myRelam);
               list.add(myRelam2);
                securityManager.setRealms(list)
         */
        //设置shiro的remember me
        securityManager.setRememberMeManager(rememberMeManager());
        securityManager.setCacheManager(ehCacheManager());
        return securityManager;
    }
    @Bean(name = "myRealm")
    public Realm realm()
    {
        MyRelam realm =new MyRelam();
        realm.setCachingEnabled(true);
        //启用身份验证缓存，即缓存AuthenticationInfo信息，默认false
        realm.setAuthenticationCachingEnabled(true);
        //缓存AuthenticationInfo信息的缓存名称 在ehcache-shiro.xml中有对应缓存的配置
        realm.setAuthenticationCacheName("authenticationCache");

        //启用授权缓存，即缓存AuthorizationInfo信息，默认false
        realm.setAuthorizationCachingEnabled(true);

        //缓存AuthorizationInfo信息的缓存名称  在ehcache-shiro.xml中有对应缓存的配置
        realm.setAuthorizationCacheName("authorizationCache");
        //realm.setCredentialsMatcher(hashedCredentialsMatcher());

        realm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher());
        return  realm;
    }

    //配置shiro整合Ehcache
    /**
     * 自定义缓存管理器
     *
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache/shiro-ehcache.xml");
        return cacheManager;
    }


    //设置themyleaf shiro解析
    @Bean
    public ShiroDialect shiroDialect(){
        return  new ShiroDialect();
    }

    //设置rememberme
    //TODO RememberMeManager
    public CookieRememberMeManager rememberMeManager(){
        //创建CookieRememberMeManager对象
        CookieRememberMeManager cookieRememberMeManager=new CookieRememberMeManager();
        //1、设置Cookie的参数(Cookie的有效期等)
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //2、对Cookie信息进行加密设置
        cookieRememberMeManager.setCipherKey("1234567898765432".getBytes());
        //返回
        return cookieRememberMeManager;
    }
    /*
    设置Cookie的信息
     */
    public SimpleCookie rememberMeCookie(){
        SimpleCookie cookie=new SimpleCookie("rememberme");
        // cookie.setDomain();
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(30*2 *60*60);
        return  cookie;
    }
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        //设置加密次数，比如两次，相当于md5(md5())
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }

    /**
     * 配置 凭证匹配器 ,加密算法为 SHA1
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcherSHA(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("SHA1");
        //设置加密次数，比如两次，相当于SHA1(SHA1())
        hashedCredentialsMatcher.setHashIterations(1024);
        return hashedCredentialsMatcher;
    }

}
